Dwango Programming Contest V (A,B,C)

800分的题目都做不出..

官方题解略长..告辞..

地址

A - Thumbnail

水签到。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;
int n, a[105];
int main() {
scanf("%d", &n);
double s = 0;
for (int i = 0; i < n; i++) scanf("%d", &a[i]), s += a[i];
s /= n;
int ans = 0;
for (int i = 1; i < n; i++)
if (fabs(a[ans]-s) > fabs(a[i]-s)) ans = i;
printf("%d\n", ans);
}

B - Sum AND Subarrays

题意

找 k 个数字使其 and 之和最大

分析

按位贪心,如果这位上 1 的个数大于 k,就把这位上是 0 的数字全部删掉,再处理下一位,小于 k 就跳过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <bits/stdc++.h>
using namespace std;
#define pw(i) (1ull<<(i))
typedef unsigned long long ull;
const int N = 1005;
int p[N], n, k;
vector<ull> a, b;
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
for (int i = 1; i <= n; i++) {
ull tmp = 0;
for (int j = i; j <= n; j++) {
tmp += p[j];
a.push_back(tmp);
}
}
ull ans = 0;
int t = 62;
while (t >= 0) {
int num = 0;
for (auto x : a) if (x&pw(t)) num++;
if (num >= k) {
ans ^= pw(t);
for (auto x : a) if (x&pw(t)) b.push_back(x);
a = b;
}
t--;
}
cout << ans << endl;
}

C - k-DMC

题意

给定长为 N 的字符串 S,Q 个询问,每个询问给一个 k,要你找三元组(a,b,c)的个数,要求

  • S[a]='D', S[b]='M', S[c] = 'C'
  • $c-a < k$

数据范围 $N \le 1e6, Q \le 75$

分析

看复杂度就知道$O(NQ)$挺合理。

枚举 'C',这样每个询问变为$O(1)$求区间内 ('D','M') 的对数。

预处理每个数字前面 'D' 的个数和每个数字前面 'M' 的个数,以及每个数字前 ('D','M') 对数,这样就可以做到$O(1)$的区间查询了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
char s[N];
int n, q;
ll D[N], M[N], DM[N];
int main() {
scanf("%d%s", &n, s+1);
for (int i = 1; i <= n; i++) {
D[i] = D[i-1], M[i] = M[i-1];
DM[i] = DM[i-1];
if (s[i] == 'D') D[i]++;
if (s[i] == 'M') M[i]++, DM[i] += D[i];
}
scanf("%d", &q);
while (q--) {
int k; scanf("%d", &k);
ll ans = 0;
for (int i = 1; i <= n; i++) {
if (s[i] == 'C') {
int j = max(0, i-k);
ans += DM[i]-DM[j]-D[j]*(M[i]-M[j]);
}
}
printf("%lld\n", ans);
}
}